package io.sage.ch06.methodrefactoring;

import io.sage.ch06.common.Order;

import java.util.Enumeration;
import java.util.Vector;

/**
 * 6.1 Extract Method（提炼函数）
 * 问题场景：有一段代码可以被组织在一起并独立出来。
 * 重构思维：处理过长的函数，将其中一段代码从原先的函数中提取出来，放入一个单独函数中，并让函数名称解释该函数的用途。
 * 困难：
 * 处理局部变量是最大困难，其中临时变量是主要困难源头。
 * 方法：
 * 1）创造一个新函数，根据这个函数的意图来对它命名。
 * 2）将提炼出得代码从源函数复制到新建的目标函数中。
 * 3）仔细检查提炼出的代码，检查其中是否引用了“作用域限于源函数”的变量（局部变量和源函数参数）
 * 4）检查是否有“仅限于被提炼代码段”的临时变量。如果有，在目标函数中将它们声明为临时变量。
 * 5）检查被提炼代码段，看看是否有任何局部变量的值被它改变。
 *    5.1 如果一个临时变量值被修改了，看看是否可以将被提炼代码段处理为一个查询，并将结果赋值给相关变量。
 *    5.2 如果被修改的变量不知一个，很多地方都使用某个临时变量，可先使用Spilt Temporary Variable【P128】将其变得容易替换。
 *        也可以使用Replace Temp with Query【P120】将临时变量消灭掉。
 *    5.3 如果临时变量太混乱，难以替换，可使用Replace Method with Method Object【P135】
 * 6）将被提炼代码段中需要读取的局部变量，当做参数传递忒目标函数
 * 7）处理完所有局部变量之后，进行编译
 * 8）在源函数中，将被提炼代码段替换为对目标函数的调用。
 * 9）编译，测试。
 *
 */

public class ExtractMethod {
    Vector<Order> _orders;
    String _name;

    /**
     * 重构前
     *
     * @param previousAmount
     */
    void printOwing(double previousAmount) {

        Enumeration e = _orders.elements();
        double outstanding = previousAmount * 1.2;

        // print banner
        System.out.println("**********************************");
        System.out.println("********* Customer Owes **********");
        System.out.println("**********************************");

        // calculate outstanding
        while (e.hasMoreElements()) {
            Order each = (Order) e.nextElement();
            outstanding += each.getAmount();
        }

        // print details
        System.out.println("name:" + _name);
        System.out.println("amount:" + outstanding);
    }


    /**
     * 重构后，将长函数或者需要注释才能让人理解的代码放进一个独立的函数中
     *
     * @param previousAmount
     */
    void printOwing_New(double previousAmount) {
        printBanner();
        double outstanding = getOutstanding(previousAmount * 1.2);
        printDetails(outstanding);
    }

    // 无局部变量的代码块直接抽取出来
    private void printBanner() {
        System.out.println("**********************************");
        System.out.println("********* Customer Owes **********");
        System.out.println("**********************************");
    }

    // 有局部变量的且不对局部变量赋值的，可通过函数参数传递给目标函数
    private void printDetails(double outstanding) {
        System.out.println("name:" + _name);
        System.out.println("amount:" + outstanding);
    }

    // 有局部变量的且对局部变量赋值的，可通过函数参数传递给目标函数，并通过函数返回值对局部变量进行赋值
    private double getOutstanding(double initialValue) {
        double result = initialValue;
        Enumeration e = _orders.elements();
        while (e.hasMoreElements()) {
            Order each = (Order) e.nextElement();
            result += each.getAmount();
        }
        return result;
    }
}
